package de.upb.aquarium.api.utility;

/**
 * Convenience class for computing with double vectors.
 * @author Jost
 */
public class VectorFloat {
	public float[] data;
	
	/**
	 * Clones the given vector.
	 * @param toClone the vector to clone.
	 */
	public VectorFloat(VectorFloat toClone)
	{
		this(toClone.data);
	}
	
	/**
	 * Creates a vector which has a clone of the given <code>data</code> as
	 * data.
	 * @param data The vector data.
	 */
	public VectorFloat(float[] data) {
		this.data = (float[])data.clone();
	}
	
	/**
	 * Create a vector containing a part of an array. 
	 * @param data The Array to copy from.
	 * @param offset the index to start copying from.
	 * @param size the number of elements to copy.
	 */
	public VectorFloat(float[] data, int offset, int size)
	{
		this.data = new float[size];
		
		for (int i = 0; i < size; i++)
		{
			this.data[i] = data[offset+i];
		}
	}
	
	/**
	 * Creates a new vector of the given size, but does not initialize it.
	 * @param size The vectors size.
	 */
	public VectorFloat(int size)
	{
		data = new float[size];
	}
	
	public VectorFloat(double[] data) {
		this.data = new float[data.length];
		
		for (int i = 0; i < data.length; i++)
		{
			this.data[i] = (float)data[i];
		}
	}

	/**
	 * Gets the size of the vector.
	 * @return The size of the vector.
	 */
	public int getSize()
	{
		return data.length;
	}
	
	/**
	 * Adds this vector to another, equally sized, one.
	 * @param rhs The other vector.
	 * @return A new vector representing <code>this + rhs</code>.
	 * @throws IllegalArgumentException If the vectors have different size.
	 */
	public VectorFloat add(VectorFloat rhs) throws IllegalArgumentException
	{
		VectorFloat result = new VectorFloat(data);
		
		if (rhs.data.length != data.length)
		{
			throw new IllegalArgumentException("Wrong vector length.");
		}
		
		for (int i = 0; i < data.length; i++)
		{
			result.data[i] += rhs.data[i];
		}
		
		return result;
	}
	
	/**
	 * Computes <code>-this</code>.
	 * @return A new vector representing the negation of this vector. 
	 */
	public VectorFloat negate()
	{
		VectorFloat result = new VectorFloat(this);
		
		for (int i = 0; i < result.data.length; i++)
		{
			result.data[i] = -result.data[i];
		}
		
		return result;
	}
	
	/**
	 * Subtracts to equally sized vectors.
	 * @param rhs The vector to subtract from this.
	 * @return A new vector representing <code>this - rhs</code>.
	 * @throws IllegalArgumentException If the vectors have different size.
	 */
	public VectorFloat sub(VectorFloat rhs) throws IllegalArgumentException
	{
		VectorFloat result = new VectorFloat(data);
		
		if (rhs.data.length != data.length)
		{
			throw new IllegalArgumentException("Wrong vector length.");
		}
		
		for (int i = 0; i < data.length; i++)
		{
			result.data[i] -= rhs.data[i];
		}
		
		return result;
	}
	
	/**
	 * Multiplies this vector with a scalar and returns the result as a
	 * new vector.
	 * @param scalar The scalar to multiply with.
	 * @return A new vector representing <code>scalar*this</code>
	 */
	public VectorFloat mul(double scalar)
	{
		VectorFloat result = new VectorFloat(data);
		
		for (int i = 0; i < data.length; i++)
		{
			result.data[i] *= scalar;
		}
		
		return result;
	}

	/**
	 * Computes the dot product of <code>rhs</code> and <code>this</code>.
	 * @param rhs The vector to compute the dot product with.
	 * @return The dot product <code>this*rhs</code> as a new vector.
	 * @throws IllegalArgumentException If the vectors do not have equal size.
	 */
	public double dot(VectorFloat rhs) throws IllegalArgumentException
	{
		double result = 0.0;
		
		if (rhs.data.length != data.length)
		{
			throw new IllegalArgumentException("Wrong vector length.");
		}
		
		for (int i = 0; i < data.length; i++)
		{
			result += data[i]*rhs.data[i];
		}
		
		return result;
	}
	
	/**
	 * Computes the cross product of two vectors of size 3.
	 * @param rhs The vector right side.
	 * @return The cross product <code>this x rhs</code> as a new vector. 
	 * @throws IllegalArgumentException If one of the vectors is not of size 3.
	 */
	public VectorFloat CrossProduct(VectorFloat rhs) throws IllegalArgumentException
	{
		if (data.length != 3 || rhs.data.length != 3)
		{
			throw new IllegalArgumentException("You tried to compute the " +
				"cross product of two vectors which do not both have size 3.");
		}
		
		VectorFloat result = new VectorFloat(data);
		
		result.data[0] = data[1]*rhs.data[2] - data[2]*rhs.data[1];
		result.data[1] = -(data[0]*rhs.data[2] - data[2]*rhs.data[0]);
		result.data[2] = data[0]*rhs.data[1] - data[1]*rhs.data[0];
		
		return result;
	}
	
	/**
	 * Normalizes this vector.
	 */
	public void normalize()
	{
		double norm = Math.sqrt(this.dot(this));
		
		for (int i = 0; i < data.length; i++)
		{
			data[i] /= norm;
		}
	}
	
	/**
	 * Computes a string representation.
	 */
	public String toString()
	{
		String result = "[";
		for (int i = 0; i < data.length-1; i++)
		{
			result += data[i] + ", ";
		}
		result += data[data.length - 1] + "]";
		
		return result;
	}
	
	/**
	 * Computes the euclidian norm of this vector.
	 * @returns the euclidian norm of this vector, i.e. its length.
	 */
	public float norm()
	{
		return (float)Math.sqrt(this.dot(this));
	}
}
